ACM/ICPC 之 SPFA范例两道(POJ3268-POJ3259)
两道以SPFA算法求解的最短路问题,比较水,第二题需要掌握如何判断负权值回路。
POJ3268-Silver Cow Party
//计算正逆最短路径之和的最大值 //Time:32Ms Memory:360K #include<iostream> #include<cstring> #include<cstdio> #include<queue> #include<algorithm> using namespace std; #define MAX 1005 #define MAXE 100005 #define INF 0x3f3f3f3f struct Edge { int v, w, next; Edge() {} Edge(int vv, int ww, int nn):v(vv), w(ww), next(nn) {} }e[2][MAXE]; int n, m, x; int h[2][MAX], d[2][MAX]; bool v[MAX]; void spfa(int x, int r) { memset(v, false, sizeof(v)); queue<int> q; q.push(x); d[r][x] = 0; while (!q.empty()){ int cur = q.front(); q.pop(); v[cur] = false; for (int i = h[r][cur]; i != -1; i = e[r][i].next) { int tv = e[r][i].v; int tw = e[r][i].w; if (d[r][tv] > d[r][cur] + tw) { d[r][tv] = d[r][cur] + tw; if (!v[tv]) { q.push(tv); v[tv] = true; } } } } } int main() { memset(d, INF, sizeof(d)); memset(h, -1, sizeof(h)); scanf("%d%d%d", &n, &m, &x); for (int i = 0; i < m; i++) { int a, b, t; scanf("%d%d%d", &a, &b, &t); if (a == b) { m--; i--; continue; } e[0][i] = Edge(b, t, h[0][a]); //正向 e[1][i] = Edge(a, t, h[1][b]); //反向 h[0][a] = h[1][b] = i; } spfa(x, 0); //正向路径找返回最短路 spfa(x, 1); //反向路径找出发最短路 int Max = 0; for (int i = 1; i <= n; i++) Max = max(d[0][i] + d[1][i], Max); printf("%d\n", Max); return 0; }
POJ3259-Wormholes
//SPFA或Bellman Ford算法 //判断是否有负权值回路 //Time:172Ms Memory:252K #include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; #define MAX 505 #define MAXN 5500 #define INF 0x3f3f3f3f struct Edge { int u, w, next; Edge() {} Edge(int uu, int ww, int nn) :u(uu), w(ww), next(nn) {} }e[MAXN]; int n, m, w; int le; int h[MAX], d[MAX]; int cnt[MAX]; bool v[MAX]; bool spfa(int x) { memset(cnt, 0, sizeof(cnt)); memset(v, false, sizeof(v)); memset(d, INF, sizeof(d)); d[x] = 0; queue<int> q; q.push(x); cnt[x] = 1; while (!q.empty()) { int cur = q.front(); q.pop(); v[cur] = false; for (int i = h[cur]; i != -1; i = e[i].next) { int u = e[i].u, w = e[i].w; if (d[u] > d[cur] + w) { d[u] = d[cur] + w; if (!v[u]) { v[u] = true; q.push(u); //如果某点入队列达到n次,则一定存在负权值回路 if (++cnt[u] == n) return true; } } } } return false; } int main() { int T; scanf("%d", &T); while (T--) { le = 0; memset(h, -1, sizeof(h)); scanf("%d%d%d", &n, &m, &w); int a, b, t; while (m--) { scanf("%d%d%d", &a, &b, &t); e[le] = Edge(b, t, h[a]); h[a] = le++; e[le] = Edge(a, t, h[b]); h[b] = le++; } while (w--) { scanf("%d%d%d", &a, &b, &t); e[le] = Edge(b, -t, h[a]); h[a] = le++; } /*如果不是连通图则需要遍历所有点 //Time:1750Ms int flag = false; for (int i = 1; i <= n; i++) if (spfa(i)) { flag = true; break; } 题目未说清是否为连通图 */ if (spfa(1)) printf("YES\n"); else printf("NO\n"); } return 0; }
他坐在湖边,望向天空,她坐在对岸,盯着湖面